skip_docs

lane :test do
  validate_repo(tool_name: detect_tool)
end

desc "Increment the version number of this gem"
lane :bump do |options|
  tool_name = options[:tool] || detect_tool
  path = "./lib/#{tool_name}/version.rb"

  latest_release = current_version(tool: tool_name)
  `open https://github.com/#{github_url(tool: tool_name)}/compare/#{latest_release}...master`

  local_version = version_get_podspec(path: path) # here, to not show the lane change

  puts "Live Version: #{latest_release}"
  puts "Local Version: #{local_version}"

  bump_type ||= 'minor' if prompt(text: "New Feature?", boolean: true)
  bump_type ||= 'patch' if bump_type.nil? && prompt(text: "Bugfix/Improvements?", boolean: true)

  if bump_type
    version_bump_podspec(path: path, bump_type: bump_type)
    git_commit(path: path,
               message: "Version Bump by fastlane")
    push_to_git_remote
  else
    puts "Doing nothing..."
  end
end

desc "Display a changelog for a tool since its last release."
desc "Run from a tool directory or specify (e.g. tool:deliver)"
lane :show_changelog do |options|
  tool_name = options[:tool] || detect_tool
  old_version = current_version(tool: tool_name)

  print_release_changelog(tool: tool_name, old_version: old_version)
end

desc "Does everything that's needed for a release"
desc "This includes running tests and verifying the GitHub release"
lane :release do |options|
  update_fastlane

  # Fetching all information required for the release
  #
  tool_name = options[:tool] || detect_tool

  # Git verification
  #
  ensure_git_status_clean
  ensure_git_branch(branch: 'master')
  git_pull

  # Verifying RubyGems version
  #
  validate_repo(tool_name: tool_name)

  require "../lib/#{tool_name}/version"
  version = module_ref(tool_name: tool_name)::VERSION
  old_version = current_version(tool: tool_name)
  puts "Deploying #{tool_name} #{version}"
  if Gem::Version.new(version) <= Gem::Version.new(old_version)
    UI.user_error!("Version number #{version} was already deployed")
  end

  # Then push to git remote
  #
  push_to_git_remote

  # Preparing GitHub Release
  #
  github_release = get_github_release(url: github_url(tool: tool_name), version: version)
  if (github_release || {}).fetch('body', '').length == 0
    print_release_changelog(tool: tool_name, old_version: old_version)

    title = prompt(text: 'Title: ')
    description = prompt(text: "Please enter a changelog: ",
                         multi_line_end_keyword: "END")

    github_release = set_github_release(
      repository_name: github_url(tool: tool_name),
      name: [version, title].join(" "),
      tag_name: version,
      description: description,
      is_draft: false
    )

    # Actual release of the gem
    #
    sh "gem push ../pkg/#{tool_name}-#{version}.gem"

    release_url = github_release['html_url']
    clipboard(value: release_url)

    message = [title, description, release_url].join("\n\n")
    add_fastlane_git_tag(tag: "#{tool_name}/#{version}", message: message)
  end

  # After publishing
  #
  if ENV['SLACK_URL']
    slack(
      channel: "releases",
      default_payloads: [],
      message: "Successfully released [#{tool_name} #{version}](#{release_url}) :rocket:",
      payload: {
        "New" => github_release['body']
      }
    )
  end

  clubmate

  puts "You can now tweet:".green
  tag_url = "https://github.com/fastlane/fastlane/releases/tag/#{tool_name}/#{version}"
  puts "[#{tool_name}] #{github_release['name']} #{tag_url}"

  update_docs
end

desc "Makes sure the tests on https://docs.fastlane.tools still work with the latest version"
lane :verify_docs do
  local_fastlane_dir = File.expand_path("../..")
  clone_docs do
    temporary_gemfile = []
    Fastlane::TOOLS.each { |tool| temporary_gemfile << "gem '#{tool}', path: '#{File.join(local_fastlane_dir, tool.to_s)}'" }
    temporary_gemfile = temporary_gemfile.join("\n")
    puts `sed -i -e "s/activate_bin_path/bin_path/g" $(which bundle)` # workaround for bundler https://github.com/bundler/bundler/issues/4602#issuecomment-233619696
    sh "bundle install"
    sh "bundle exec fastlane test skip_building:true" # skip_building since we don't have a proper python environment set up
  end
end

desc "Update the actions.md on https://docs.fastlane.tools"
desc "This will also automatically submit a pull request to fastlane/docs"
lane :update_docs do
  if ENV["ENHANCER_USER"].to_s.length == 0 || ENV["ENHANCER_PASSWORD"].to_s.length == 0
    UI.error("No ENHANCER_USER or ENHANCER_PASSWORD environment variables found, which are required to generate a new Actions.md")
    next
  end

  clone_docs do
    require 'fastlane/documentation/markdown_docs_generator'
    actions_md_path = File.expand_path("docs/actions.md")
    Fastlane::MarkdownDocsGenerator.new.generate!(target_path: actions_md_path)

    if `git status --porcelain`.length == 0
      UI.success("No changes in the actions.md ✅")
    else
      # Create a new branch
      sh "git checkout -b 'update-actions-md-#{Time.now.to_i}'"

      Dir.chdir("fastlane") do # this is an assumption of fastlane, that we have to .. when shelling out
        # Commit the changes
        git_commit(path: actions_md_path, message: "Update actions.md for latest fastlane release 🚀")
        # Push them to the git remote
        push_to_git_remote

        # Submit the pull request
        pr_url = create_pull_request(
          api_token: ENV["FL_GITHUB_RELEASE_API_TOKEN"],
          repo: "fastlane/docs",
          title: "[Bot] Update actions.md for latest fastlane release 🚀",
          body: "Auto-generated by fastlane bot 🤖"
        )
        UI.success("Successfully submitted a pull request to fastlane/docs: #{pr_url} 🚀")
      end
    end
  end
end

def clone_docs
  require 'tmpdir'
  git_url = "https://github.com/fastlane/docs"

  Dir.mktmpdir("fl_clone") do
    sh "git clone #{git_url} --depth=1"
    Dir.chdir("docs") do
      yield
    end
  end
end

error do |lane, exception|
  if ENV['SLACK_URL']
    slack(channel: "testing", message: exception.to_s, success: false)
  end
end

desc "Verifies all tests pass and the current state of the repo is valid"
private_lane :validate_repo do |options|
  # Verifying that no debug code is in the code base
  #
  ensure_no_debug_code(text: "pry", extension: ".rb", path: "./lib/") # debugging code
  ensure_no_debug_code(text: "# TODO", extension: ".rb", path: "./lib/") # TODOs
  ensure_no_debug_code(text: "now: ", extension: ".rb", path: "./lib/") # rspec focus
  ensure_no_debug_code(text: "<<<<<<<", extension: ".rb", path: "./lib/") # Merge conflict

  rubocop

  # Verifying the --help command
  #
  tool_name = options[:tool_name]
  binary_path = File.join("..", "bin", tool_name)
  unless no_binary.include? tool_name
    content = sh "PAGER=cat #{binary_path} --help"
    ["--version", "https://fastlane.tools", tool_name].each do |current|
      UI.user_error!("--help missing information: '#{current}'") unless content.include? current
    end
  end

  # Running ruby things
  #
  sh "cd .. && bundle install"
  sh "cd .. && rake install"

  # Run the tests
  #
  rspec

  # Verify docs are still working
  verify_docs
end

desc "e.g. fastlane/deliver"
private_lane :github_url do |options|
  if options[:tool] == "fastlane"
    "fastlane/fastlane"
  else
    File.join("fastlane-old", options[:tool])
  end
end

desc "Get the version number of the last release"
private_lane :current_version do |options|
  puts "Checking the latest version on RubyGems"
  download(url: "https://rubygems.org/api/v1/gems/#{options[:tool]}.json")["version"]
end

desc "All repos that don't have a binary to test"
private_lane :no_binary do
  ['fastlane_core', 'spaceship', 'credentials_manager']
end

desc "Detects the name of the tool based on the current directory"
private_lane :detect_tool do
  Dir["../*.gemspec"].last.match(/(\w+).gemspec/)[1]
end

desc "Get a reference to the module of this tool"
desc "This method can be overwritten by the individual Fastfiles of the tools (e.g. PEM)"
private_lane :module_ref do |options|
  Object.const_get(options[:tool_name].split('_').collect(&:capitalize).join)
end

desc "Print out the changelog since the last tagged release"
private_lane :print_release_changelog do |options|
  tool_name = options[:tool]
  old_version = options[:old_version]

  changes = Actions.sh("git log --pretty='* %s' #{tool_name}/#{old_version}...HEAD --no-merges ..", log: false).gsub("\n\n", "\n")
  changes.gsub!("[#{tool_name}] ", "") # some commits are pre-fixed with the tool name in [ ]

  puts "Changes since release #{old_version}:\n\n#{changes.cyan}"
end

desc "Add a git tag in the fastlane repo for this release"
private_lane :add_fastlane_git_tag do |options|
  `git tag -am #{options[:message].shellescape} #{options[:tag].shellescape}`
  push_git_tags
end
